using System;
using System.Text;
using System.Collections.Generic;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;
using Microsoft.Xna.Framework.Net;
using Microsoft.Xna.Framework.Storage;
using Komires.MataliPhysics;
using WiimoteLib;

namespace MySimpleScene
{
    public class SimpleCameraAnimation1
    {
        Game1 demo;
        PhysicsScene scene;
        string instanceIndexName;

        string sphereName;
        string shotName;

        Shape sphere;

        Wiimote wm = new Wiimote();

        float positionX1 = 0;
        float oldpositionX1 = 0;
        float positionY1 = 0;
        float oldpositionY1 = 0;
        float positionX2 = 0;
        float oldpositionX2 = 0;
        float positionY2 = 0;
        float oldpositionY2 = 0;

        float accelX1 = 0;
        float accelY1 = 0;
        float accelX2 = 0;
        float accelY2 = 0;

#if XBOX360
        GamePadState oldPadState;
#else
        MouseState oldMouseState;
        KeyboardState oldKeyboardState;
        WiimoteState oldWiiModeState;
#endif

        Vector3 position;
        Vector3 direction;
        Matrix rotation;
        Matrix cameraRotation;
        Matrix oldcameraRotation;

        Vector3 vectorZero;
        Matrix matrixIdentity;
        Quaternion quaternionIdentity;
        Vector3 oldPosition;

        public SimpleCameraAnimation1(Game1 demo, int instanceIndex)
        {
            this.demo = demo;
            instanceIndexName = " " + instanceIndex.ToString();

            sphereName = "Shot";
            shotName = "Simple Camera Shot" + instanceIndexName + " ";

            vectorZero = Vector3.Zero;
            matrixIdentity = Matrix.Identity;
            quaternionIdentity = Quaternion.Identity;

            // Create a new wiimote
            wm = new Wiimote();

            // Check wether the status of the Wiimote has changed - NOT REALLY SURE
            /*wm.WiimoteChanged += wm_WiimoteChanged;
            wm.WiimoteExtensionChanged += wm_WiimoteExtensionChanged;*/

            // Connect the Wiimote
            wm.Connect();

            // set the report type to return the IR sensor and accelerometer data (buttons always come back)
            wm.SetReportType(InputReport.IRAccel, true);
        }

        public void Initialize(PhysicsScene scene)
        {
            this.scene = scene;
        }

        public void SetControllers()
        {
            sphere = scene.Factory.ShapeManager.Find("Shot");

#if XBOX360
            oldPadState = GamePad.GetState(PlayerIndex.One);
#else
            // test update
            oldMouseState = Mouse.GetState();
            oldKeyboardState = Keyboard.GetState();
#endif

            PhysicsObject objectBase = scene.Factory.PhysicsObjectManager.Find("Simple Camera" + instanceIndexName);
            if (objectBase != null)
            {
                objectBase.UserControllers.PostTransformMethods += new SimulateMethod(Move);
            }
        }

        public void RefreshControllers()
        {
#if XBOX360
            oldPadState = GamePad.GetState(PlayerIndex.One);
#else
            oldMouseState = Mouse.GetState();
            oldKeyboardState = Keyboard.GetState();
            oldWiiModeState = wm.WiimoteState;
#endif
        }

      /*  private void wm_WiimoteChanged(object sender, WiimoteChangedEventArgs args)
        {
            //wiimoteInfo1.UpdateState(args);
        }

        private void wm_WiimoteExtensionChanged(object sender, WiimoteExtensionChangedEventArgs args)
        {
            //wiimoteInfo1.UpdateExtension(args);

            if (args.Inserted)
                wm.SetReportType(InputReport.IRExtensionAccel, true);    // return extension data
            else
                wm.SetReportType(InputReport.IRAccel, true);           // back to original mode
        }*/

        public void Move(SimulateMethodArgs args)
        {
            // Get the physics scene and the objects it manages
            PhysicsScene scene = demo.Engine.Factory.PhysicsSceneManager.Get(args.OwnerSceneIndex);
            PhysicsObject objectBase = scene.Factory.PhysicsObjectManager.Get(args.OwnerIndex);

            if (!objectBase.Camera.Enabled) return;
            if (!objectBase.Camera.Active) return;

            float time = (float)args.Time;

            Vector3 deltaRotation = vectorZero;
            Vector3 deltaTranslation = vectorZero;
            float rotationSpeed = 4.0f;
            float translationSpeed = 8.0f;
            bool enableShot = false;

            // Get state of different controllers
            MouseState mouseState = Mouse.GetState();
            WiimoteState wiimoteState = wm.WiimoteState;
            KeyboardState keyboardState = Keyboard.GetState();

            // Control the view movement with the mouse
            deltaRotation.Y += MathHelper.ToRadians(rotationSpeed * (mouseState.X - oldMouseState.X) * time);
            deltaRotation.X += MathHelper.ToRadians(rotationSpeed * (mouseState.Y - oldMouseState.Y) * time);

            // Record the position of a few IR sensors
            positionX1 = wiimoteState.IRState.IRSensors[0].RawPosition.X;
            positionY1 = wiimoteState.IRState.IRSensors[0].RawPosition.Y;
            positionX2 = wiimoteState.IRState.IRSensors[3].RawPosition.X;
            positionY2 = wiimoteState.IRState.IRSensors[3].RawPosition.Y;

            accelX1 = wm.WiimoteState.AccelState.RawValues.X;
            accelY1 = wm.WiimoteState.AccelState.RawValues.Y;
                  
            // Horizontal Movement
            if (positionX1 < oldpositionX1)
            {
                deltaRotation.Y += MathHelper.ToRadians(rotationSpeed * (oldpositionX1 - positionX1) * time);   
            }
     
            if (positionX1 > oldpositionX1)
            {
                deltaRotation.Y -= MathHelper.ToRadians(rotationSpeed * (positionX1 - oldpositionX1) * time);
            }

            // Vertical Movement
            if (positionY1 < oldpositionY1)
            {
                deltaRotation.X -= MathHelper.ToRadians(rotationSpeed * (oldpositionY1 - positionY1) * time);
            }

            if (positionY1 > oldpositionY1)
            {
                deltaRotation.X += MathHelper.ToRadians(rotationSpeed * (positionY1 - oldpositionY1) * time);
            }

            // Wiimote Button Movement
            if (wiimoteState.ButtonState.Left == true)
                deltaTranslation.X -= translationSpeed * time * 2;

            if (wiimoteState.ButtonState.Right == true)
                deltaTranslation.X += translationSpeed * time * 2;

            if (wiimoteState.ButtonState.Up == true)
                deltaTranslation.Z += translationSpeed * time * 2; 

            if (wiimoteState.ButtonState.Down == true)
                deltaTranslation.Z -= translationSpeed * time * 2;

            // Launch a bullet in the screen - 
            // Need to be fixed -> It fires many bullets even if you press the button once 
            if (wiimoteState.ButtonState.B == true)
                enableShot = true;
                   
            // Mouse control
            /*if ((mouseState.MiddleButton == ButtonState.Pressed) && (oldMouseState.MiddleButton == ButtonState.Released))
                enableShot = true;

            if (mouseState.LeftButton == ButtonState.Pressed)
                enableShot = true;*/

            // Keyboard Control
            if (keyboardState.IsKeyDown(Keys.Z))         
                deltaTranslation.Z += translationSpeed * time * 2;

            if (keyboardState.IsKeyDown(Keys.S))
                deltaTranslation.Z -= translationSpeed * time * 2;

            if (keyboardState.IsKeyDown(Keys.D))
                deltaTranslation.X += translationSpeed * time * 2;

            if (keyboardState.IsKeyDown(Keys.Q))
                deltaTranslation.X -= translationSpeed * time * 2;

            // Check whether or not the Wiimote is found by IR Sensors
            if (wiimoteState.IRState.IRSensors[0].Found)
            {
                oldPosition = position;
                oldcameraRotation = cameraRotation;
            }

            // Save the previous state of controllers / IR sensors in order to compare them when the method will be used again
            oldMouseState = mouseState;
            oldKeyboardState = keyboardState;
            oldWiiModeState = wiimoteState;
            oldpositionX1 = oldWiiModeState.IRState.IRSensors[0].RawPosition.X;
            oldpositionY1 = oldWiiModeState.IRState.IRSensors[0].RawPosition.Y;
            oldpositionX2 = oldWiiModeState.IRState.IRSensors[3].RawPosition.X;
            oldpositionY2 = oldWiiModeState.IRState.IRSensors[3].RawPosition.Y;

            accelX2 = wm.WiimoteState.AccelState.RawValues.X;
            accelY2 = wm.WiimoteState.AccelState.RawValues.Y;

            // Check for no IR detected and keep the same value as before in order to stabilise the view     

            // Camera - Should not be needed to tweak this
            if (deltaRotation.LengthSquared() != 0.0f)
            {

                Vector3 euler = vectorZero;
                objectBase.Camera.GetEuler(ref euler);
                Vector3.Add(ref euler, ref deltaRotation, out euler);
                objectBase.Camera.SetEuler(ref euler);

                Matrix rotationX, rotationY;
                Matrix.CreateRotationX(-euler.X, out rotationX);
                Matrix.CreateRotationY(-euler.Y, out rotationY);
                Matrix.Multiply(ref rotationY, ref rotationX, out cameraRotation);

                // Check IR state and fix the position of the camera if both IRsensors are not found
                if (wiimoteState.IRState.IRSensors[0].Found == false && wiimoteState.IRState.IRSensors[3].Found == false)
                {
                    objectBase.Camera.SetRotation(ref oldcameraRotation);
                    objectBase.MainWorldTransform.SetTransposeRotation(ref oldcameraRotation);
                    //cameraRotation = oldcameraRotation;
                }

                // Normal behavior when IR state are found
                if (wiimoteState.IRState.IRSensors[0].Found == true)
                {
                    objectBase.Camera.SetRotation(ref cameraRotation);
                    objectBase.MainWorldTransform.SetTransposeRotation(ref cameraRotation);
                    //cameraRotation = oldcameraRotation;
                }

                //objectBase.Camera.SetRotation(ref cameraRotation);             
                //objectBase.MainWorldTransform.SetTransposeRotation(ref cameraRotation);
                objectBase.RecalculateMainTransform();
            }

            // Camera - Should not be needed to tweak this
            if (deltaTranslation.LengthSquared() != 0.0f)
            {

                if (wiimoteState.IRState.IRSensors[0].Found == false)
                {
                    position = oldPosition;
                }

                objectBase.MainWorldTransform.GetRotation(ref rotation);
                Vector3.Transform(ref deltaTranslation, ref rotation, out direction);

                objectBase.MainWorldTransform.GetPosition(ref position);
                Vector3.Add(ref position, ref direction, out position);
                objectBase.MainWorldTransform.SetPosition(ref position);

                objectBase.RecalculateMainTransform(); 
            }

            objectBase.Camera.Projection.CreatePerspectiveLH(1.0f, 10000.0f, 70.0f, demo.Window.ClientBounds.Width, demo.Window.ClientBounds.Height);

            objectBase.MainWorldTransform.GetPosition(ref position);
            objectBase.Camera.GetTransposeRotation(ref cameraRotation);

            // Set a fix position to the height of the player - This makes impossible to move everywhere in the scene
            position.Y = 3;

            objectBase.Camera.View.CreateLookAtLH(ref position, ref cameraRotation, 0.0f);
            objectBase.Camera.UpdateFrustum();

            // Code for throwing a ball in the scene
            if (enableShot)
            {
                if (wiimoteState.ButtonState.B == true && wiimoteState.ButtonState.A == true)
                {
                    PhysicsObject shot = scene.Factory.PhysicsObjectManager.Create(shotName + scene.SimulationFrameCount.ToString());

                    shot.Shape = sphere;
                    shot.UserTagStr = sphereName;

                    Vector3 shotScale = vectorZero;

                    // Scale of the ball
                    shotScale.X = shotScale.Y = shotScale.Z = 0.5f;

                    objectBase.MainWorldTransform.GetPosition(ref position);
                    objectBase.Camera.GetTransposeRotation(ref cameraRotation);

                    direction.X = cameraRotation.M31;
                    direction.Y = cameraRotation.M32;
                    direction.Z = cameraRotation.M33;

                    position.Y = 3;

                    // Speed at which the object is thrown in the air - To modify later for realistic physic
                    Vector3.Multiply(ref direction, 30.0f, out direction);

                    shot.InitLocalTransform.SetRotation(ref matrixIdentity);
                    shot.InitLocalTransform.SetPosition(ref position);
                    shot.InitLocalTransform.SetScale(ref shotScale);

                    shot.InitLocalTransform.SetLinearVelocity(ref direction);
                    shot.InitLocalTransform.SetAngularVelocity(ref vectorZero);
                    shot.Integral.SetDensity(10.0f);
                    shot.InitLocalTransform.SetScale(1.5f);
                    shot.Material.Restitution = 0.75f;
                    shot.EnableCollisions = true;
                    shot.DisableCollision(objectBase, true);
                    shot.MaxDisableCollisionFrameCount = 10;

                    if (shot.CollisionPairCount > 10)
                        shot.EnableCollisions = false;

                    scene.UpdateFromInitLocalTransform(shot);

                }    
            }

            objectBase.Camera.UpdatePhysicsObjects(true, true);
            objectBase.Camera.SortDrawPhysicsObjects(PhysicsCameraSortOrderType.DrawPriorityShapePrimitiveType);
            objectBase.Camera.SortTransparentPhysicsObjects(PhysicsCameraSortOrderType.DrawPriorityShapePrimitiveType);
        }

        public void SetWiiPosition(float position)
        {
            float positionString = position;

            //return positionString;
        }
    }
}
